package http

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"time"
)

func HttpPost(url string, data string, connTimeoutMs int, serveTimeoutMs int, contentType string) ([]byte, error) {
	fName := "HttpPost"
	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				c, err := net.DialTimeout(netw, addr, time.Duration(connTimeoutMs)*time.Millisecond)
				if err != nil {
					return nil, err
				}
				err = c.SetDeadline(time.Now().Add(time.Duration(serveTimeoutMs) * time.Millisecond))
				if err != nil {
					return nil, err
				}
				return c, nil
			},
			TLSHandshakeTimeout:   5 * time.Second,
			ResponseHeaderTimeout: 10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	body := strings.NewReader(data)
	reqest, _ := http.NewRequest("POST", url, body)
	if len(contentType) > 0 {
		reqest.Header.Set("Content-Type", contentType)
	} else {
		reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	response, err := client.Do(reqest)
	if err != nil {
		return nil, fmt.Errorf("%s http failed, POST url:%s, reason:%s", fName, url, err)
		//return nil, fmt.Errorf("%s http failed, POST url:%s, reason:%s", fName, url, err.Error())
	}
	defer response.Body.Close()

	var errMsg string
	if response.StatusCode != 200 {
		errMsg += fmt.Sprintf("http status %d ", response.StatusCode)
	}

	res_body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		errMsg += fmt.Sprintf("can't read response %s ", err.Error())
	}

	if len(errMsg) > 0 {
		errMsg += fmt.Sprintf("body :%s", string(res_body))
		err = errors.New(errMsg)
	}

	if err != nil {
		return res_body, fmt.Errorf("%s%s", fName, err.Error())
	}

	return res_body, nil
}

func HttpGet(url string, connTimeoutMs int, serveTimeoutMs int, headerPara map[string]string) ([]byte, error) {
	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				c, err := net.DialTimeout(netw, addr, time.Duration(connTimeoutMs)*time.Millisecond)
				if err != nil {
					return nil, err
				}
				err = c.SetDeadline(time.Now().Add(time.Duration(serveTimeoutMs) * time.Millisecond))
				if err != nil {
					return nil, err
				}
				return c, nil
			},
			TLSHandshakeTimeout:   5 * time.Second,
			ResponseHeaderTimeout: 10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	reqest, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	if len(headerPara) > 0 {
		for ind, val := range headerPara {
			reqest.Header.Add(ind, val)
		}
	}
	response, err := client.Do(reqest)
	if err != nil {
		return nil, fmt.Errorf("http failed, GET url:%s, reason:%s", url, err.Error())
	}
	defer response.Body.Close()

	var errMsg string
	if response.StatusCode != 200 {
		errMsg += fmt.Sprintf("http status %d ", response.StatusCode)
	}

	res_body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		errMsg += fmt.Sprintf("can't read response %s ", err.Error())
	}

	if len(errMsg) > 0 {
		errMsg += fmt.Sprintf("url :%s ", url)
		err = errors.New(errMsg)
	}

	return res_body, err
}

func HttpHParaPost(url string, headPara map[string]string, data string, connTimeoutMs int, serveTimeoutMs int) ([]byte, error) {
	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				c, err := net.DialTimeout(netw, addr, time.Duration(connTimeoutMs)*time.Millisecond)
				if err != nil {
					return nil, err
				}
				err = c.SetDeadline(time.Now().Add(time.Duration(serveTimeoutMs) * time.Millisecond))
				if err != nil {
					return nil, err
				}
				return c, nil
			},
			TLSHandshakeTimeout:   5 * time.Second,
			ResponseHeaderTimeout: 10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	body := strings.NewReader(data)
	reqest, _ := http.NewRequest("POST", url, body)
	// 请求头检查，大于0就设置
	if len(headPara) > 0 {
		for k, v := range headPara {
			reqest.Header.Add(k, v)
		}
	}
	if _, ok := headPara["Content-Type"]; !ok {
		reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	response, err := client.Do(reqest)
	if err != nil {
		return nil, fmt.Errorf("http failed, POST url:%s, reason:%s", url, err.Error())
	}
	defer response.Body.Close()

	var errMsg string
	if response.StatusCode != 200 {
		errMsg += fmt.Sprintf("http status %d ", response.StatusCode)
	}

	res_body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		errMsg += fmt.Sprintf("can't read response %s ", err.Error())
	}

	if len(errMsg) > 0 {
		errMsg += fmt.Sprintf("url :%s ", url)
		err = errors.New(errMsg)
	}

	return res_body, err
}
